package com.salon.interceptor;

import com.salon.common.annotation.CiphertextData;
import com.salon.common.annotation.CiphertextField;
import com.salon.common.utils.AesUtils;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;
import javax.annotation.Resource;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.springframework.stereotype.Component;

/**
 * 数据库脱敏加密拦截器
 */
@Component
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class ParameterInterceptor implements Interceptor {

    @Resource
    ResultSetInterceptor resultSetInterceptor;

    @Resource
    AesUtils aesUtils;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object object = invocation.getArgs()[1];
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        if (SqlCommandType.INSERT.equals(sqlCommandType)) {
            Class<?> clazz = object.getClass();
            boolean isContain = clazz.isAnnotationPresent(CiphertextData.class);
            if (isContain) {
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    boolean isContainCiphertextField = field.isAnnotationPresent(CiphertextField.class);
                    if (isContainCiphertextField) {
                        field.setAccessible(true);
                        Object o = field.get(object);
                        if (o != null) {
                            String content = aesUtils.aesHexEncrypt(String.valueOf(o));
                            field.set(object, content);
                        }
                    }
                }
            }
        } else if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
            Class temp = object.getClass();
            boolean res = temp.isAnnotationPresent(CiphertextData.class);
            if (res) {
                Field[] fields = temp.getDeclaredFields();
                for (Field field : fields) {
                    boolean isContainCiphertextField = field.isAnnotationPresent(CiphertextField.class);
                    if (isContainCiphertextField) {
                        field.setAccessible(true);
                        Object o = field.get(object);
                        if (o != null) {
                            String content = aesUtils.aesHexEncrypt(String.valueOf(o));
                            field.set(object, content);
                        }
                    }
                }
            } else {
                if (object instanceof MapperMethod.ParamMap) {
                    Map map = (Map) object;
                    boolean boll = map.containsKey("param1");
                    Object obj = null;
                    if (boll) {
                        obj = map.get("param1");
                    } else {
                        obj = map.get("et");
                    }
                    Field[] fields = obj.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        boolean isContainCiphertextField = field.isAnnotationPresent(CiphertextField.class);
                        if (isContainCiphertextField) {
                            field.setAccessible(true);
                            Object o = field.get(obj);
                            if (o != null) {
                                String content = aesUtils.aesHexEncrypt(String.valueOf(o));
                                field.set(obj, content);
                            }
                        }
                    }
                }
            }

        }
        //执行SQL方法
        Object result = invocation.proceed();
        //还原实体类被加密过的字段
        if (object instanceof MapperMethod.ParamMap) {
            Map map = (Map) object;
            if (map.containsKey("param1")) {
                resultSetInterceptor.deal(map.get("param1"));
            } else {
                resultSetInterceptor.deal(map.get("et"));
            }
        } else {
            resultSetInterceptor.deal(invocation.getArgs()[1]);
        }
        return result;
    }


    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

}
